home *** CD-ROM | disk | FTP | other *** search
/ Deutsche Edition 1 / Deutsche Edition 1.iso / amok / amok_lha / amok24.lha / DME / SRC / source.zoo / keyboard.c < prev    next >
C/C++ Source or Header  |  1989-07-03  |  17KB  |  623 lines

  1.  
  2. /*
  3.  *  KEYBOARD.C
  4.  *
  5.  *      (C)Copyright 1987 by Matthew Dillon
  6.  *
  7.  *  Handle keyboard related stuff such as keyboard mappings.  Every time
  8.  *  a key is pressed, KEYCTL() is called with the code.  KEYCTL() remembers
  9.  *  which qualifier keys are currently held down, and when a non-qualifier
  10.  *  key is pressed finds the hash entry for the key.  If no hash entry
  11.  *  exists (e.g. you type a normal 'a') the default keymap is used.
  12.  */
  13.  
  14. #include "defs.h"
  15. #include <stdio.h>
  16.  
  17. extern ubyte *cqtoa();
  18.  
  19. typedef struct IOStdReq CIO;
  20.  
  21. #define QUAL_SHIFT   0x01
  22. #define QUAL_CTRL    0x02
  23. #define QUAL_AMIGA   0x04
  24. #define QUAL_ALT     0x08
  25. #define QUAL_LMB     0x10
  26. #define QUAL_MMB     0x20
  27. #define QUAL_RMB     0x40
  28.  
  29. #define HASHSIZE  64                /*  power of 2  */
  30. #define HASHMASK  (HASHSIZE-1)
  31.  
  32. typedef struct _HASH {
  33.     struct _HASH *next;     /* next hash   */
  34.     ubyte code;             /* keycode     */
  35.     ubyte mask;             /* qual. mask  */
  36.     ubyte qual;             /* qual. comp  */
  37.     ubyte stat;             /* string static? */
  38.     char *str;              /* command string */
  39. } HASH;
  40.  
  41. HASH *Hash[HASHSIZE];
  42.  
  43. extern PROC *proc;
  44.  
  45. struct Device *ConsoleDevice;
  46.  
  47. ubyte   ctoa[128];
  48. ubyte   cstoa[128];
  49.  
  50. void
  51. keyctl(im, code, qual)
  52. IMESS *im;
  53. register USHORT qual;
  54. {
  55.     ubyte buf[256];
  56.     ubyte c2;
  57.     short blen = 0;
  58.  
  59.     code &= 0xFF;
  60.     if (im) {
  61.         im->Qualifier &= ~IEQUALIFIER_REPEAT;
  62.         blen = DeadKeyConvert(im, buf+1, 254, NULL);
  63.         if (blen < 0)
  64.             return;
  65.     }
  66.     c2 = 0;
  67.     if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  68.         c2 |= QUAL_SHIFT;
  69.     if (qual & (IEQUALIFIER_CONTROL))
  70.         c2 |= QUAL_CTRL;
  71.     if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND))
  72.         c2 |= QUAL_AMIGA;
  73.     if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
  74.         c2 |= QUAL_ALT;
  75.     if ((qual & IEQUALIFIER_CAPSLOCK) && (blen == 1) && (buf[1] > ' ') )
  76.         c2 |= QUAL_SHIFT;
  77.     if (qual & IEQUALIFIER_LEFTBUTTON)
  78.         c2 |= QUAL_LMB;
  79.     if (qual & IEQUALIFIER_MIDBUTTON)
  80.         c2 |= QUAL_MMB;
  81.     if (qual & (IEQUALIFIER_RBUTTON))
  82.         c2 |= QUAL_RMB;
  83.  
  84.     {
  85.         register HASH *hash;
  86.         for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  87.             if (hash->code == code && (c2 & hash->mask) == hash->qual)
  88.                 break;
  89.         }
  90.  
  91.         /*
  92.          *  Use hash entry only if not in command line mode, or if the
  93.          *  entry does not correspond to an alpha key.
  94.          */
  95.  
  96.         if (hash) {
  97.             if (c2 || !Comlinemode || blen > 1 || !ctoa[code]) {
  98.                 strcpy(buf, hash->str);
  99.                 do_command(buf);
  100.                 return;
  101.             }
  102.         }
  103.     }
  104.  
  105.     /*
  106.      *  No hash entry
  107.      */
  108.  
  109.     if (blen == 1) {
  110.         buf[0] = '\'';
  111.         buf[2] = 0;
  112.     } else {
  113.         buf[0] = '\`';
  114.         buf[blen+1] = '\'';
  115.     }
  116.     if (blen)
  117.         do_command(buf);
  118. }
  119.  
  120. dealloc_hash()
  121. {
  122.     register HASH *hash, *hnext = NULL;
  123.     register short i;
  124.  
  125.     for (i = 0; i < HASHSIZE; ++i) {
  126.         for (hash = Hash[i]; hash; hash = hnext) {
  127.             hnext = hash->next;
  128.             if (!hash->stat)
  129.                 FreeMem(hash->str, strlen(hash->str)+1);
  130.             FreeMem(hash, sizeof(HASH));
  131.         }
  132.         Hash[i] = NULL;
  133.     }
  134. }
  135.  
  136. resethash()
  137. {
  138.     register short i;
  139.     CIO cio;
  140.     static struct {
  141.         char *from, *to;
  142.     } defmap[] = {
  143.         "esc",      "esc",
  144.         "c-esc",    "recall",
  145.         "return",   "return insline up firstnb down",
  146.         "enter",    "return",
  147.         "up",       "up",
  148.         "down",     "down",
  149.         "right",    "right",
  150.         "left",     "left",
  151.         "bs",       "bs",
  152.         "del",      "del",
  153.         "tab",      "tab",
  154.         "a-up",     "scrollup",
  155.         "a-down",   "scrolldown",
  156.         "a-r",      "nextr",
  157.         "a-u",      "while cl (tlate -32 right)",
  158.         "a-l",      "while cu (tlate +32 right)",
  159.         "s-up",     "top",
  160.         "s-down",   "bottom",
  161.         "s-right",  "last",
  162.         "s-left",   "first",
  163.         "s-tab",    "backtab",
  164.         "s-del",    "deline",
  165.         "s- ",      "( )",              /* shift space to space */
  166.         "c-1",      "goto block",
  167.         "c-c",      "",                 /* break.. map to a nop */
  168.         "c-l",      "wleft",
  169.         "c-r",      "wright",
  170.         "c-i",      "insertmode on",
  171.         "c-o",      "insertmode off",
  172.         "c-j",      "join",
  173.         "c-s",      "split first down",
  174.         "c-del",    "remeol",
  175.         "c-n",      "next",
  176.         "c-p",      "prev",
  177.         "c-/",      "escimm (find )",
  178.         "c-]",      "ref",
  179.         "c-[",      "ctags",
  180.         "c-g",      "escimm (goto )",
  181.         "c-up",     "pageup",
  182.         "c-down",   "pagedown",
  183.         "c-q",      "quit",
  184.         "c-f",      "reformat",
  185.         "c-w",      "wordwrap toggle",
  186.         "f1",       "escimm (insfile )",
  187.         "f2",       "escimm (newfile )",
  188.         "f3",       "escimm (newwindow newfile )",
  189.         "f6",       "saveold iconify",
  190.         "f7",       "escimm (bsave )",
  191.         "f8",       "saveold escimm (newfile )",
  192.         "f9",       "saveold",
  193.         "f10",      "saveold quit",
  194.         "c-b",      "block",
  195.         "c-u",      "unblock",
  196.         "a-d",      "bdelete",
  197.         "a-c",      "bcopy",
  198.         "a-m",      "bmove",
  199.         "a-s",      "bsource",
  200.         "a-S",      "unblock block block bsource",
  201.         "L-lmb",    "tomouse",      /*  left button                 */
  202.         "L-mmo",    "tomouse",      /*  mouse move w/left held down */
  203.         "R-rmb",    "iconify",      /*  right button                */
  204.         NULL, NULL
  205.     };
  206.  
  207.     dealloc_hash();
  208.     OpenDevice("console.device", -1, &cio, 0);
  209.     ConsoleDevice = cio.io_Device;
  210.     keyboard_init();
  211.     for (i = 0; defmap[i].from; ++i) {
  212.         ubyte code, qual;
  213.         if (get_codequal(defmap[i].from, &code, &qual))
  214.             addhash(code, 1, 0xFF, qual, defmap[i].to);
  215.     }
  216. }
  217.  
  218. returnoveride(n)
  219. {
  220.     HASH *hash;
  221.     static ubyte *str;
  222.     static int stat;
  223.  
  224.     for (hash = Hash[0x44&HASHMASK]; hash; hash = hash->next) {
  225.         if (hash->code == 0x44 && hash->qual == 0) {
  226.             if (n) {
  227.                 str = (ubyte *)hash->str;
  228.                 stat= hash->stat;
  229.                 hash->str = "return";
  230.                 hash->stat = 1;
  231.             } else {
  232.                 if (str == NULL) {
  233.                     remhash(0x44, -1, 0);
  234.                 } else {
  235.                     hash->str = (char *)str;
  236.                     hash->stat= stat;
  237.                 }
  238.             }
  239.             return(0);
  240.         }
  241.     }
  242.     if (n) {
  243.         addhash(0x44, 1, 0xFF, 0, "return");
  244.         str = NULL;
  245.     }
  246. }
  247.  
  248.  
  249. addhash(code, stat, mask, qual, str)
  250. ubyte code, stat, mask, qual;
  251. ubyte *str;
  252. {
  253.     register HASH **p, *hash;
  254.  
  255.     hash = *(p = &Hash[code&HASHMASK]);
  256.     while (hash) {
  257.         if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  258.             if (!hash->stat)
  259.                 FreeMem(hash->str, strlen(hash->str)+1);
  260.             goto newstr;
  261.         }
  262.         hash = *(p = &hash->next);
  263.     }
  264.     *p = hash = (HASH *)AllocMem(sizeof(HASH), 0);
  265.     hash->next = NULL;
  266. newstr:
  267.     hash->code = code;
  268.     hash->stat = stat;
  269.     hash->mask = mask;
  270.     hash->qual = qual;
  271.     hash->str = (char *)str;
  272.     if (!stat)                  /* if not static */
  273.         hash->str = (char *)strcpy(AllocMem(strlen(str)+1, 0), str);
  274. }
  275.  
  276.  
  277. remhash(code, mask, qual)
  278. ubyte code, mask, qual;
  279. {
  280.     register HASH *hash, **p;
  281.  
  282.     hash = *(p = &Hash[code&HASHMASK]);
  283.     while (hash) {
  284.         if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  285.             if (!hash->stat)
  286.                 FreeMem(hash->str, strlen(hash->str)+1);
  287.             *p = hash->next;
  288.             FreeMem(hash, sizeof(HASH));
  289.             return(1);
  290.         }
  291.         hash = *(p = &hash->next);
  292.     }
  293.     return(0);
  294. }
  295.  
  296. char *
  297. keyspectomacro(str)
  298. char *str;
  299. {
  300.     HASH *hash;
  301.     ubyte code, qual;
  302.  
  303.     if (get_codequal(str, &code, &qual)) {
  304.         for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  305.             if (hash->code == code) {
  306.                 if (hash->qual == (qual & hash->mask)) {
  307.                     return(hash->str);
  308.                 }
  309.             }
  310.         }
  311.     }
  312.     return(NULL);
  313. }
  314.  
  315.  
  316. do_map()
  317. {
  318.     ubyte code, qual;
  319.  
  320.     if (get_codequal(av[1], &code, &qual)) {
  321.         addhash(code, 0, 0xFF, qual, av[2]);
  322.     } else {
  323.         title("Unknown Key");
  324.     }
  325. }
  326.  
  327. do_unmap()        /* key   */
  328. {
  329.     ubyte code, qual;
  330.  
  331.     if (get_codequal(av[1], &code, &qual)) {
  332.         remhash(code, -1, qual);
  333.     } else {
  334.         title("Unknown Command");
  335.     }
  336. }
  337.  
  338. do_clearmap()
  339. {
  340.     resethash();
  341. }
  342.  
  343. /*
  344.  * SAVEMAP  file
  345.  * SAVESMAP file
  346.  */
  347.  
  348. do_savemap()
  349. {
  350.     char sysalso;
  351.     char err = 0;
  352.     char buf[256];
  353.     long xfi;
  354.     register int i;
  355.     register HASH *hash;
  356.     register ubyte *ptr;
  357.  
  358.     proc->pr_WindowPtr = (APTR) Ep->Win;
  359.     xfi = xfopen(av[1], "w", 512);
  360.     if (xfi) {
  361.         sysalso = av[0][4] == 's';
  362.         for (i = 0; i < HASHSIZE; ++i) {
  363.             for (hash = Hash[i]; hash; hash = hash->next) {
  364.                 if (hash->stat == 0 || sysalso) {
  365.                     char soc = '(';
  366.                     char eoc = ')';
  367.                     char ksoc = '(';
  368.                     char keoc = ')';
  369.                     short len;
  370.  
  371.                     for (ptr = (ubyte *)hash->str; *ptr; ++ptr) {
  372.                         if (*ptr == '(')
  373.                             break;
  374.                         if (*ptr == '\`') {
  375.                             soc = '\`';
  376.                             eoc = '\'';
  377.                             break;
  378.                         }
  379.                     }
  380.                     len = strlen(ptr = cqtoa(hash->code, hash->qual)) - 1;
  381.                     if (ptr[len] == '(' || ptr[len] == ')') {
  382.                         ksoc = '\`';
  383.                         keoc = '\'';
  384.                     }
  385.                     sprintf(buf, "map %c%s%c %c%s%c\n", ksoc, cqtoa(hash->code, hash->qual), keoc, soc, hash->str, eoc);
  386.                     xfwrite(xfi, buf, strlen(buf));
  387.                 }
  388.             }
  389.         }
  390.         xfclose(xfi);
  391.         if (err)
  392.             title ("Unable to Write");
  393.         else
  394.             title ("OK");
  395.     } else {
  396.         title("Unable to open file");
  397.     }
  398. }
  399.  
  400. /*
  401.  *  Nitty Gritty.
  402.  *
  403.  *  keyboard_init:  initialize for get_codequal() and cqtoa()
  404.  *  get_codequal:   convert a qualifier-string combo to a keycode and qual.
  405.  *  cqtoa:          convert a keycode and qual to a qual & string
  406.  */
  407.  
  408. #define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)
  409.  
  410. long lname[] = {
  411.     LN('e','s','c', 0  ), LN('f','1', 0 , 0  ), LN('f','2', 0 , 0  ),
  412.     LN('f','3', 0 , 0  ), LN('f','4', 0 , 0  ), LN('f','5', 0 , 0  ),
  413.     LN('f','6', 0 , 0  ), LN('f','7', 0 , 0  ), LN('f','8', 0 , 0  ),
  414.     LN('f','9', 0 , 0  ), LN('f','1','0', 0  ), LN('d','e','l', 0  ),
  415.     LN('b','a','c', 0  ), LN('b','s', 0 , 0  ), LN('t','a','b', 0  ),
  416.     LN('h','e','l', 0  ), LN('r','e','t', 0  ), LN('u','p', 0 , 0  ),
  417.     LN('d','o','w', 0  ), LN('r','i','g', 0  ), LN('l','e','f', 0  ),
  418.     LN('e','n','t', 0  ), LN('n','k','-', 0  ), LN('n','k','.', 0  ),
  419.     LN('n','k','0', 0  ),   /* 24 */
  420.     LN('n','k','1', 0  ), LN('n','k','2', 0  ), LN('n','k','3', 0  ),
  421.     LN('n','k','4', 0  ), LN('n','k','5', 0  ), LN('n','k','6', 0  ),
  422.     LN('n','k','7', 0  ), LN('n','k','8', 0  ), LN('n','k','9', 0  ),
  423.     LN('n','k','(', 0  ), LN('n','k',')', 0  ), LN('n','k','/', 0  ), /*34-36*/
  424.     LN('n','k','*', 0  ), LN('n','k','+', 0  ),
  425.     LN('l','m','b',0xE8), LN('m','m','b',0xEA), LN('r','m','b',0xE9),
  426.     LN('m','m','o',QMOVE),
  427.     0
  428. };
  429.  
  430.  
  431. /*
  432.  *  ESC:        x1B
  433.  *  FUNCKEYS:   x9B 30 7E to x9B 39 7E
  434.  *  DEL:        x7E
  435.  *  BS:         x08
  436.  *  TAB:        x09
  437.  *  RETURN:     x0D
  438.  *  HELP        x9B 3F 7E
  439.  *  UP/D/L/R    x9B 41/42/44/43
  440.  *  NK0-9,-,.,ENTER
  441.  *
  442.  *  Mouse buttons
  443.  */
  444.  
  445. keyboard_init()
  446. {
  447.     static struct InputEvent ievent = { NULL, IECLASS_RAWKEY };
  448.     ubyte buf[32];
  449.     register short i, q, len;
  450.  
  451.     lname[16] |= 0x44;
  452.     lname[21] |= 0x43;
  453.  
  454.     for (i = 0; i < 128; ++i) {
  455.         ievent.ie_Code = i;
  456.         ievent.ie_Qualifier = 0;
  457.         ievent.ie_position.ie_addr = NULL;
  458.         len = RawKeyConvert(&ievent,buf,32,NULL);
  459.         switch(len) {
  460.         case 1:     /*  ESC/DEL/BS/TAB/NKx  */
  461.             if (buf[0] >= 32 && buf[0] < 127)
  462.                 ctoa[i] = buf[0];
  463.             switch(buf[0]) {
  464.             case 0x1B:  lname[ 0] |= i; break;
  465.             case 0x7F:  lname[11] |= i; break;
  466.             case 0x09:  lname[14] |= i; break;
  467.             case 0x08:  lname[12] |= i; lname[13] |= i; break;
  468.             case '(': if (i > 0x3A) lname[34] |= i; break;
  469.             case ')': if (i > 0x3A) lname[35] |= i; break;
  470.             case '/': if (i > 0x3A) lname[36] |= i; break;
  471.             case '*': if (i > 0x3A) lname[37] |= i; break;
  472.             case '-': if (i > 0x3A) lname[22] |= i; break;
  473.             case '+': if (i > 0x3A) lname[38] |= i; break;
  474.             case '.': if (i > 0x3A) lname[23] |= i; break;
  475.             default:
  476.                 if (i >= 0x0F && buf[0] >= '0' && buf[0] <= '9')
  477.                     lname[24+buf[0]-'0'] |= i;
  478.             }
  479.             break;
  480.         case 2:     /*  cursor              */
  481.             if (buf[0] == 0x9B) {
  482.                 switch(buf[1]) {
  483.                 case 0x41:  lname[17] |= i;  break;
  484.                 case 0x42:  lname[18] |= i;  break;
  485.                 case 0x43:  lname[19] |= i;  break;
  486.                 case 0x44:  lname[20] |= i;  break;
  487.                 }
  488.             }
  489.             break;
  490.         case 3:     /*  function/help       */
  491.             if (buf[0] == 0x9B && buf[2] == 0x7E) {
  492.                 if (buf[1] == 0x3F)
  493.                     lname[15] |= i;
  494.                 if (buf[1] >= 0x30 && buf[1] <= 0x39)
  495.                     lname[buf[1]-0x30+1] |= i;
  496.             }
  497.             break;
  498.         }
  499.     }
  500.     for (i = 0; i < 128; ++i) {
  501.         ievent.ie_Code = i;
  502.         ievent.ie_Qualifier = IEQUALIFIER_LSHIFT;
  503.         ievent.ie_position.ie_addr = NULL;
  504.         len = RawKeyConvert(&ievent,buf,32,NULL);
  505.         if (len == 1)
  506.             cstoa[i] = buf[0];
  507.     }
  508.     {
  509.         ubyte code, qual;
  510.         get_codequal("c", &code, &qual);
  511.         CtlC = code;
  512.     }
  513. }
  514.  
  515.  
  516. ubyte *
  517. cqtoa(code, qual)
  518. register int qual;
  519. {
  520.     static ubyte buf[32];
  521.     register ubyte *ptr = buf;
  522.     register int i;
  523.  
  524.     if (qual & QUAL_SHIFT)
  525.         *ptr++ = 's';
  526.     if (qual & QUAL_CTRL)
  527.         *ptr++ = 'c';
  528.     if (qual & QUAL_ALT)
  529.         *ptr++ = 'a';
  530.     if (qual & QUAL_AMIGA)
  531.         *ptr++ = 'A';
  532.     if (qual & QUAL_LMB)
  533.         *ptr++ = 'L';
  534.     if (qual & QUAL_MMB)
  535.         *ptr++ = 'M';
  536.     if (qual & QUAL_RMB)
  537.         *ptr++ = 'R';
  538.     if (qual)
  539.         *ptr++ = '-';
  540.     for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) {
  541.         if ((lname[i]&0xFF) == code) {
  542.             *ptr++ = (lname[i]>>24);
  543.             *ptr++ = (lname[i]>>16);
  544.             *ptr++ = (lname[i]>>8);
  545.             break;
  546.         }
  547.     }
  548.     if (i == sizeof(lname)/sizeof(lname[0]))
  549.         *ptr++ = ctoa[code];
  550.     *ptr++ = 0;
  551.     return(buf);
  552. }
  553.  
  554.  
  555. get_codequal(str, pcode, pqual)
  556. ubyte *pcode, *pqual;
  557. register ubyte *str;
  558. {
  559.     register ubyte qual;
  560.     register short i;
  561.  
  562.     qual = 0;
  563.     if (strlen(str) > 1) {
  564.         for (; *str && *str != '-'; ++str) {
  565.             if (*str == 's')
  566.                 qual |= QUAL_SHIFT;
  567.             if (*str == 'c')
  568.                 qual |= QUAL_CTRL;
  569.             if (*str == 'a')
  570.                 qual |= QUAL_ALT;
  571.             if (*str == 'A')
  572.                 qual |= QUAL_AMIGA;
  573.             if (*str == 'L')
  574.                 qual |= QUAL_LMB;
  575.             if (*str == 'M')
  576.                 qual |= QUAL_MMB;
  577.             if (*str == 'R')
  578.                 qual |= QUAL_RMB;
  579.             if (!qual)
  580.                 goto notqual;
  581.         }
  582.         if (*str)
  583.             ++str;
  584.     }
  585. notqual:
  586.     if (strlen(str) != 1) {           /* long name   */
  587.         register short shift = 24;
  588.         register long mult = 0;
  589.  
  590.         *pqual = qual;
  591.         while (*str && shift >= 8) {
  592.             if (*str >= 'A' && *str <= 'Z')
  593.                 *str = *str - 'A' + 'a';
  594.             mult |= *str << shift;
  595.             shift -= 8;
  596.             ++str;
  597.         }
  598.         for (i = 0; lname[i]; ++i) {
  599.             if (mult == (lname[i] & 0xFFFFFF00)) {
  600.                 *pcode = lname[i] & 0xFF;
  601.                 return(1);
  602.             }
  603.         }
  604.     } else {                /*  single character keycap */
  605.         for (i = 0; i < sizeof(ctoa); ++i) {
  606.             if (*str == ctoa[i]) {
  607.                 *pcode = i;
  608.                 *pqual = qual;
  609.                 return(1);
  610.             }
  611.         }
  612.         for (i = 0; i < sizeof(cstoa); ++i) {
  613.             if (*str == cstoa[i]) {
  614.                 *pcode = i;
  615.                 *pqual = qual|QUAL_SHIFT;
  616.                 return(1);
  617.             }
  618.         }
  619.     }
  620.     return(0);
  621. }
  622.  
  623.